package com.rybbaby.tss.core.utils;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.font.TextAttribute;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Position;
import net.coobird.thumbnailator.geometry.Positions;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import com.rybbaby.tss.core.utils.pojo.Size;

/**
 * @description 图片处理工具
 * 
 * @author 谢进伟
 * 
 * @createDate 2016年11月14日 上午9:50:13
 */
public class ThumbnailsUtils {
	
	private static Logger log = Logger.getLogger(ThumbnailsUtils.class);
	
	/**
	 * 生成缩略图
	 * 
	 * @param originalImgFilePath
	 *            原图片文件路径
	 * @param keepAspectRatio
	 *            是否保存比例<br>
	 *            当 keepAspectRatio为true时:<br>
	 *            若图片横比width小，高比height小，不变<br>
	 *            若图片横比width小，高比height大，高缩小到height，图片比例不变<br>
	 *            若图片横比width大，高比height小，横缩小到width，图片比例不变<br>
	 *            若图片横比width大，高比height大，图片按比例缩小，横为width或高为height<br>
	 * @param width
	 *            宽度
	 * @param height
	 *            高度
	 * @return 缩略图文件对象
	 * 
	 */
	public static ThumbnailsResult thumbnail(String originalImgFilePath , boolean keepAspectRatio , Size size) {
		return thumbnail(new File(originalImgFilePath) , keepAspectRatio , size);
	}
	
	/**
	 * 生成缩略图
	 * 
	 * @param originalImgFile
	 *            原图片文件
	 * @param keepAspectRatio
	 *            是否保存比例<br>
	 *            当 keepAspectRatio为true时:<br>
	 *            若图片横比width小，高比height小，不变<br>
	 *            若图片横比width小，高比height大，高缩小到height，图片比例不变<br>
	 *            若图片横比width大，高比height小，横缩小到width，图片比例不变<br>
	 *            若图片横比width大，高比height大，图片按比例缩小，横为width或高为height<br>
	 * @param width
	 *            宽度
	 * @param height
	 *            高度
	 * @return 缩略图文件对象
	 * 
	 */
	public static ThumbnailsResult thumbnail(File originalImgFile , boolean keepAspectRatio , Size size) {
		int width = size.getWidth();
		int height = size.getHeight();
		log.info("正在生成图片：" + originalImgFile.getPath() + " " + width + " X " + height + " 的缩略图...");
		int resCode = 1;
		String errorMsg = "处理成功";
		File thumbnailFile = null;
		try {
			String fileName = originalImgFile.getName();
			if(fileName.contains("-")) {
				String [] split = fileName.split("-");// 型如：随机串-原文件名-随机数.后缀
				if(split.length == 3) {
					fileName = split[1] + "." + StringUtils.substringAfterLast(fileName , ".");
				}
			}
			String prefix = StringUtils.substringBeforeLast(fileName , ".");
			String suffix = StringUtils.substringAfterLast(fileName , ".");
			File parentFile = originalImgFile.getParentFile();
			String path = parentFile.getPath();
			String thumbnailFilePath = path + File.separator + prefix + "-" + width + "-" + height + "." + suffix;
			thumbnailFile = new File(thumbnailFilePath);
			if(thumbnailFile.exists()) {
				thumbnailFile.delete();
			}
			Thumbnails.of(originalImgFile)// 加载原图
			.size(width , height)// 指定压缩大小
			.keepAspectRatio(false)// 不按比例缩放
			.toFile(thumbnailFile);// 写入到新文件
			if(thumbnailFile.exists()) {
				log.info("生成缩略图成功,缩略图路径：" + thumbnailFilePath);
			} else {
				resCode = 0;
				errorMsg = "生成缩略图失败!";
				log.info(errorMsg);
			}
		} catch (IOException e) {
			resCode = 0;
			errorMsg = "生成缩略图过程中发生异常,异常信息:" + e.getMessage();
			log.info(errorMsg);
			e.printStackTrace();
		}
		return new ThumbnailsResult(resCode , errorMsg , thumbnailFile);
	}
	
	/**
	 * 对图片进行图片水印
	 * 
	 * @param originalImgFilePath
	 *            原图片路径
	 * @param watermarkImgFilePath
	 *            水印图片路径
	 * @param x
	 *            水印图片区左上角x坐标
	 * @param y
	 *            水印图片区左上角y坐标
	 * @param positions
	 *            水印位置
	 * @param opacity
	 *            透明度(取值0到1)
	 * @return 水印之后的图片
	 */
	public static ThumbnailsResult watermark(String originalImgFilePath , String watermarkImgFilePath , int x , int y , float opacity) {
		return watermark(new File(originalImgFilePath) , new File(watermarkImgFilePath) , new Position() {
			
			@Override
			public Point calculate(int enclosingWidth , int enclosingHeight , int width , int height , int insetLeft , int insetRight , int insetTop , int insetBottom) {
				int p_x = x + insetLeft;
				int p_y = y + insetTop;
				return new Point(p_x , p_y);
			}
			
		} , opacity);
	}
	
	/**
	 * 对图片进行图片水印
	 * 
	 * @param originalImgFilePath
	 *            原图片路径
	 * @param watermarkImgFilePath
	 *            水印图片路径
	 * @param positions
	 *            水印位置
	 * @param opacity
	 *            透明度(取值0到1)
	 * @return 水印之后的图片
	 */
	public static ThumbnailsResult watermark(String originalImgFilePath , String watermarkImgFilePath , Positions positions , float opacity) {
		return watermark(new File(originalImgFilePath) , new File(watermarkImgFilePath) , positions , opacity);
	}
	
	/**
	 * 对图片进行图片水印
	 * 
	 * @param originalImgFile
	 *            原图片
	 * @param watermarkImgFile
	 *            水印图片
	 * @param x
	 *            水印图片区左上角x坐标
	 * @param y
	 *            水印图片区左上角y坐标
	 * @param positions
	 *            水印位置
	 * @param opacity
	 *            透明度(取值0到1)
	 * @return 水印之后的图片
	 */
	public static ThumbnailsResult watermark(File originalImgFile , File watermarkImgFile , int x , int y , float opacity) {
		return watermark(originalImgFile , watermarkImgFile , new Position() {
			
			@Override
			public Point calculate(int enclosingWidth , int enclosingHeight , int width , int height , int insetLeft , int insetRight , int insetTop , int insetBottom) {
				int p_x = x + insetLeft;
				int p_y = y + insetTop;
				return new Point(p_x , p_y);
			}
			
		} , opacity);
	}
	
	/**
	 * 对图片进行图片水印
	 * 
	 * @param originalImgFile
	 *            原图片
	 * @param watermarkImgFile
	 *            水印图片
	 * @param positions
	 *            水印位置
	 * @param opacity
	 *            透明度(取值0到1)
	 * @return 水印之后的图片
	 */
	public static ThumbnailsResult watermark(File originalImgFile , File watermarkImgFile , Position position , float opacity) {
		log.info("正在对图片：" + originalImgFile.getPath() + "进行图片水印...");
		int resCode = 1;
		String errorMsg = "处理成功";
		File watermarkFile = null;
		try {
			String fileName = originalImgFile.getName();
			String prefix = StringUtils.substringBeforeLast(fileName , ".");
			String suffix = StringUtils.substringAfterLast(fileName , ".");
			File parentFile = originalImgFile.getParentFile();
			String path = parentFile.getPath();
			String thumbnailFilePath = path + File.separator + prefix + "_watermark." + suffix;
			watermarkFile = new File(thumbnailFilePath);
			if(watermarkFile.exists()) {
				watermarkFile.delete();
			}
			opacity = Math.min(Math.max(Math.max(opacity , 0) , opacity) , 1);
			BufferedImage read_originalImgFile = ImageIO.read(originalImgFile);
			int width = read_originalImgFile.getWidth();// 原始图宽度
			int height = read_originalImgFile.getHeight();// 原始图高度
			Thumbnails.of(originalImgFile)// 加载原图
			.size(width , height)// 设置宽高
			.watermark(position , ImageIO.read(watermarkImgFile) , 0.5f)// 水印位置及透明度
			.outputQuality(1f)// 不采取压缩,直接输出
			.toFile(watermarkFile);// 写入到新的文件
			if(watermarkFile.exists()) {
				log.info("水印成功,水印图片路径：" + thumbnailFilePath);
			} else {
				resCode = 0;
				errorMsg = "水印失败!";
				log.info(errorMsg);
			}
		} catch (IOException e) {
			resCode = 0;
			errorMsg = "图片水印过程中发生异常,异常信息:" + e.getMessage();
			log.info(errorMsg);
			e.printStackTrace();
		}
		return new ThumbnailsResult(resCode , errorMsg , watermarkFile);
	}
	
	/**
	 * 图片文字水印
	 * 
	 * @param originalImgFilePath
	 *            需要添加水印的图片的路径
	 * @param markContent
	 *            水印的文字
	 * @return
	 */
	public static ThumbnailsResult watermark(String originalImgFilePath , String markContent) {
		Color markContentColor = Color.WHITE;
		float qualNum = 1;
		String fontType = "黑体";
		int fontSize = 20;
		return watermark(new File(originalImgFilePath) , markContent , markContentColor , qualNum , fontType , fontSize);
	}
	
	/**
	 * 图片文字水印
	 * 
	 * @param originalImgFilePath
	 *            需要添加水印的图片
	 * @param markContent
	 *            水印的文字
	 * @return
	 */
	public static ThumbnailsResult watermark(File originalImgFile , String markContent) {
		Color markContentColor = Color.WHITE;
		float qualNum = 1;
		String fontType = "黑体";
		int fontSize = 20;
		return watermark(originalImgFile , markContent , markContentColor , qualNum , fontType , fontSize);
	}
	
	/**
	 * 图片文字水印
	 * 
	 * @param filePath
	 *            需要添加水印的图片的路径
	 * @param markContent
	 *            水印的文字
	 * @param markContentColor
	 *            水印文字的颜色
	 * @param qualNum
	 *            图片质量
	 * @param fontType
	 *            字体
	 * @param fontsize
	 *            字体大小
	 * @return
	 */
	public static ThumbnailsResult watermark(String originalImgFilePath , String markContent , Color markContentColor , float qualNum , String fontType , int fontSize) {
		return watermark(new File(originalImgFilePath) , markContent , markContentColor , qualNum , fontType , fontSize);
		
	}
	
	/**
	 * 给图片添加水印
	 * 
	 * @param filePath
	 *            需要添加水印的图片的路径
	 * @param markContent
	 *            水印的文字
	 * @param markContentColor
	 *            水印文字的颜色
	 * @param qualNum
	 *            图片质量
	 * @param fontType
	 *            字体
	 * @param fontsize
	 *            字体大小
	 * @return
	 */
	@SuppressWarnings("restriction")
	public static ThumbnailsResult watermark(File originalImgFile , String markContent , Color markContentColor , float qualNum , String fontType , int fontSize) {
		log.info("正在对图片：" + originalImgFile.getPath() + "进行文字水印...");
		int resCode = 1;
		String errorMsg = "处理成功";
		InputStream fis = null;
		OutputStream fos = null;
		FileOutputStream out = null;
		File watermarkFile = null;
		try {
			String fileName = originalImgFile.getName();
			String prefix = StringUtils.substringBeforeLast(fileName , ".");
			String suffix = StringUtils.substringAfterLast(fileName , ".");
			File parentFile = originalImgFile.getParentFile();
			String path = parentFile.getPath();
			String watermarkFilePath = path + File.separator + prefix + "_watermark." + suffix;
			watermarkFile = new File(watermarkFilePath);
			fis = new FileInputStream(originalImgFile);
			fos = new FileOutputStream(watermarkFile);
			IOUtils.copy(fis , fos);
			String filePath = watermarkFile.getPath();
			ImageIcon imgIcon = new ImageIcon(filePath);
			Image theImg = imgIcon.getImage();
			int width = theImg.getWidth(null);
			int height = theImg.getHeight(null);
			BufferedImage bimage = new BufferedImage(width , height , BufferedImage.TYPE_INT_RGB);
			Graphics2D g = bimage.createGraphics();
			g.setColor(markContentColor);
			g.setBackground(Color.white);
			g.drawImage(theImg , 0 , 0 , null);
			AttributedString ats = new AttributedString(markContent);
			Font f = new Font(fontType , Font.BOLD , fontSize);
			ats.addAttribute(TextAttribute.FONT , f , 0 , markContent.length());
			AttributedCharacterIterator iter = ats.getIterator();
			g.drawString(iter , width / 5 , height / 5);
			g.dispose();
			out = new FileOutputStream(filePath);
			com.sun.image.codec.jpeg.JPEGImageEncoder encoder = com.sun.image.codec.jpeg.JPEGCodec.createJPEGEncoder(out);
			com.sun.image.codec.jpeg.JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage);
			param.setQuality(qualNum , true);
			encoder.encode(bimage , param);
			out.close();
			log.info("图片文字水印成功,水印图片路径:" + watermarkFile.getPath());
		} catch (Exception e) {
			resCode = 0;
			errorMsg = "图片文字水印过程中发生异常,异常信息:" + e.getMessage();
			log.info(errorMsg);
			e.printStackTrace();
		} finally {
			IOUtils.closeQuietly(out);
			IOUtils.closeQuietly(fos);
			IOUtils.closeQuietly(fis);
		}
		return new ThumbnailsResult(resCode , errorMsg , watermarkFile);
	}
	
	/**
	 * 图片裁剪
	 * 
	 * @param originalImgFile
	 *            原图路径
	 * @param x
	 *            裁剪区左上角x坐标
	 * @param y
	 *            裁剪区左上角y坐标
	 * @param width
	 *            相对于裁剪区左上角的裁剪宽度
	 * @param height
	 *            相对于裁剪区左上角的裁剪高度
	 * @return
	 */
	public static ThumbnailsResult crop(String originalImgFilePath , int x , int y , int width , int height) {
		return crop(new File(originalImgFilePath) , x , y , width , height);
	}
	
	/**
	 * 图片裁剪
	 * 
	 * @param originalImgFile
	 *            原图
	 * @param x
	 *            裁剪区左上角x坐标
	 * @param y
	 *            裁剪区左上角y坐标
	 * @param width
	 *            相对于裁剪区左上角的裁剪宽度
	 * @param height
	 *            相对于裁剪区左上角的裁剪高度
	 * @return
	 */
	public static ThumbnailsResult crop(File originalImgFile , int x , int y , int width , int height) {
		return crop(originalImgFile , new Position() {
			
			@Override
			public Point calculate(int enclosingWidth , int enclosingHeight , int width , int height , int insetLeft , int insetRight , int insetTop , int insetBottom) {
				int p_x = x + insetLeft;
				int p_y = y + insetTop;
				return new Point(p_x , p_y);
			}
			
		} , width , height);
	}
	
	/**
	 * 图片裁剪
	 * 
	 * @param originalImgFile
	 *            原图路径
	 * @param position
	 *            裁剪区左上角坐标位置
	 * @param width
	 *            相对于裁剪区左上角的裁剪宽度
	 * @param height
	 *            相对于裁剪区左上角的裁剪高度
	 * @return
	 */
	public static ThumbnailsResult crop(String originalImgFilePath , Position positions , int width , int height) {
		return crop(new File(originalImgFilePath) , positions , width , height);
	}
	
	/**
	 * 图片裁剪
	 * 
	 * @param originalImgFile
	 *            原图
	 * @param position
	 *            裁剪区左上角坐标位置
	 * @param width
	 *            相对于裁剪区左上角的裁剪宽度
	 * @param height
	 *            相对于裁剪区左上角的裁剪高度
	 * @return
	 */
	public static ThumbnailsResult crop(File originalImgFile , Position positions , int width , int height) {
		log.info("正在对图片：" + originalImgFile.getPath() + "进行裁剪...");
		int resCode = 1;
		String errorMsg = "处理成功";
		File cropFile = null;
		try {
			String fileName = originalImgFile.getName();
			String prefix = StringUtils.substringBeforeLast(fileName , ".");
			String suffix = StringUtils.substringAfterLast(fileName , ".");
			File parentFile = originalImgFile.getParentFile();
			String path = parentFile.getPath();
			String cropFilePath = path + File.separator + prefix + "_crop." + suffix;
			cropFile = new File(cropFilePath);
			if(cropFile.exists()) {
				cropFile.delete();
			}
			BufferedImage read_originalImgFile = ImageIO.read(originalImgFile);
			int origImgWidth = read_originalImgFile.getWidth();// 原始图宽度
			int origImgHeight = read_originalImgFile.getHeight();// 原始图高度
			Thumbnails.of(originalImgFile)// 加载文件
			.size(Math.min(origImgWidth , width) , Math.min(origImgHeight , height))// 设置大小
			.sourceRegion(positions , width , height)// 裁剪
			.toFile(cropFile);
			if(cropFile.exists()) {
				log.info("裁剪成功,水印图片路径：" + cropFilePath);
			} else {
				resCode = 0;
				errorMsg = "裁剪失败!";
				log.info(errorMsg);
			}
		} catch (IOException e) {
			resCode = 0;
			errorMsg = "图片水印过程中发生异常,异常信息:" + e.getMessage();
			log.info(errorMsg);
			e.printStackTrace();
		}
		return new ThumbnailsResult(resCode , errorMsg , cropFile);
	}
	
	public static class ThumbnailsResult {
		
		/** 处理结果码 **/
		private int resCode = 1;
		/** 处理发送错误的时候的错误信息 **/
		private String errorMsg = "处理成功";
		/** 处理后产生的文件 **/
		private File file;
		
		/**
		 * @param file
		 *            处理后产生的文件
		 */
		public ThumbnailsResult (File file ){
			super();
			this.file = file;
		}
		
		/**
		 * @param resCode
		 *            处理结果码
		 * @param errorMsg
		 *            处理发送错误的时候的错误信息
		 */
		public ThumbnailsResult (int resCode , String errorMsg ){
			super();
			this.resCode = resCode;
			this.errorMsg = errorMsg;
		}
		
		public ThumbnailsResult (int resCode , String errorMsg , File file ){
			super();
			this.resCode = resCode;
			this.errorMsg = errorMsg;
			this.file = file;
		}
		
		/**
		 * @return 处理结果码 1表示成功,0表示失败
		 */
		public int getResCode() {
			return resCode;
		}
		
		public void setResCode(int resCode) {
			this.resCode = resCode;
		}
		
		/**
		 * @return 处理发送错误的时候的错误信息
		 */
		public String getErrorMsg() {
			return errorMsg;
		}
		
		public void setErrorMsg(String errorMsg) {
			this.errorMsg = errorMsg;
		}
		
		/**
		 * @return 处理后产生的文件
		 */
		public File getFile() {
			return file;
		}
		
		public void setFile(File file) {
			this.file = file;
		}
		
	}
}
